package com.fiill.audioplayer;
import android.media.AudioFormat;
import android.media.AudioAttributes;
import android.util.Log;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class Utils {
    private static final String TAG = "BAHAL_UTILS";

    public static int getBitFormatFromFormatStr(String bit_format_format_str) {
        if(bit_format_format_str.equals("ENCODING_PCM_16BIT")) return AudioFormat.ENCODING_PCM_16BIT; //2
        if(bit_format_format_str.equals("ENCODING_DEFAULT")) return AudioFormat.ENCODING_DEFAULT; // 1
        else if(bit_format_format_str.equals("ENCODING_PCM_8BIT")) return AudioFormat.ENCODING_PCM_8BIT; // 3
        else if(bit_format_format_str.equals("ENCODING_PCM_FLOAT")) return AudioFormat.ENCODING_PCM_FLOAT; //4
        else if(bit_format_format_str.equals("ENCODING_PCM_24BIT_PACKED")) return AudioFormat.ENCODING_PCM_24BIT_PACKED; // 21
        else if(bit_format_format_str.equals("ENCODING_PCM_32BIT")) return AudioFormat.ENCODING_PCM_32BIT; // 22
        else return 0;
    }

    public static int getBitFormatFromBitWidth(int width) {
        if(16 == width) return AudioFormat.ENCODING_PCM_16BIT; //2
        else if(8 == width) return AudioFormat.ENCODING_PCM_8BIT; // 3
        else if(24 == width) return AudioFormat.ENCODING_PCM_24BIT_PACKED; //21
        else if(32 == width) return AudioFormat.ENCODING_PCM_32BIT; // 22
        else return AudioFormat.ENCODING_DEFAULT;
    }

    public static int getBitWidthFromFormat(int format) {
        if(format == AudioFormat.ENCODING_DEFAULT) return 2;
        else if(format == AudioFormat.ENCODING_PCM_16BIT) return 2;
        else if(format == AudioFormat.ENCODING_PCM_8BIT) return 1;
        else if(format == AudioFormat.ENCODING_PCM_FLOAT) return 4;
        else if(format == AudioFormat.ENCODING_PCM_24BIT_PACKED) return 3;
        else if(format == AudioFormat.ENCODING_PCM_32BIT) return 4;
        else return 0;
    }

    public static int channelMaskFromOutChannelMaskString(String channel_mask_str) {
        if(channel_mask_str.equals("CHANNEL_OUT_MONO")) return AudioFormat.CHANNEL_OUT_MONO;
        if(channel_mask_str.equals("CHANNEL_OUT_STEREO")) return AudioFormat.CHANNEL_OUT_STEREO;
        else if(channel_mask_str.equals("CHANNEL_OUT_5POINT1")) return AudioFormat.CHANNEL_OUT_5POINT1;
        else if(channel_mask_str.equals("CHANNEL_OUT_7POINT1POINT4")) return AudioFormat.CHANNEL_OUT_7POINT1POINT4;
        else if(channel_mask_str.equals("CHANNEL_OUT_7POINT1_SURROUND")) return AudioFormat.CHANNEL_OUT_7POINT1_SURROUND;
        else if(channel_mask_str.equals("CHANNEL_OUT_QUAD")) return AudioFormat.CHANNEL_OUT_QUAD;
        else if(channel_mask_str.equals("CHANNEL_OUT_5POINT1POINT4")) return AudioFormat.CHANNEL_OUT_5POINT1POINT4;
        else return 0;
    }

    public static int channelMaskFromChannelCount(int channels) {
        if(1 == channels) return AudioFormat.CHANNEL_OUT_MONO;
        if(2 == channels) return AudioFormat.CHANNEL_OUT_STEREO;
        else if(6 == channels) return AudioFormat.CHANNEL_OUT_5POINT1;
        else if(12 == channels) return AudioFormat.CHANNEL_OUT_7POINT1POINT4;
        else if(8 == channels) return AudioFormat.CHANNEL_OUT_7POINT1_SURROUND;
        else if(4 == channels) return AudioFormat.CHANNEL_OUT_QUAD;
        else if(10 == channels) return AudioFormat.CHANNEL_OUT_5POINT1POINT4;
        else return AudioFormat.CHANNEL_OUT_MONO;
    }

    public static boolean hasFileExtension(String filename, String extension) {
        return filename.toLowerCase().endsWith("." + extension);
    }

    public static boolean mergePCMFilesToWAVFile(List<String> filePathList,
                                                 String destinationPath) {
        File[] file = new File[filePathList.size()];
        byte buffer[] = null;

        int TOTAL_SIZE = 0;
        int fileNum = filePathList.size();

        for (int i = 0; i < fileNum; i++) {
            file[i] = new File(filePathList.get(i));
            TOTAL_SIZE += file[i].length();
        }

        WaveHeader header = new WaveHeader();
 
        header.fileLength = TOTAL_SIZE + (44 - 8);
        header.FmtHdrLeth = 16;
        header.BitsPerSample = 16; //16 bit
        header.Channels = (short)AudioFormat.channelCountFromInChannelMask(WaveHeader.IN_CHANNELS);
        header.FormatTag = 0x0001;
        header.SamplesPerSec = WaveHeader.RATE;
        header.BlockAlign = (short) (header.Channels * header.BitsPerSample / 8);
        header.AvgBytesPerSec = header.BlockAlign * header.SamplesPerSec;
        header.DataHdrLeth = TOTAL_SIZE;

        byte[] h = null;
        try {
            h = header.getHeader();
        } catch (IOException e1) {
            Log.e(TAG, e1.getMessage());
            return false;
        }

        if (h.length != 44)
            return false;

        File destfile = new File(destinationPath);
        if (destfile.exists())
            destfile.delete();

        try {
            buffer = new byte[1024 * 4]; // Length of All Files, Total Size
            InputStream inStream = null;
            OutputStream ouStream = null;

            ouStream = new BufferedOutputStream(new FileOutputStream(
                    destinationPath));
            ouStream.write(h, 0, h.length);
            for (int j = 0; j < fileNum; j++) {
                inStream = new BufferedInputStream(new FileInputStream(file[j]));
                int size = inStream.read(buffer);
                while (size != -1) {
                    ouStream.write(buffer);
                    size = inStream.read(buffer);
                }
                inStream.close();
            }
            ouStream.close();
        } catch (FileNotFoundException e) {
            Log.e(TAG, e.getMessage());
            return false;
        } catch (IOException ioe) {
            Log.e(TAG, ioe.getMessage());
            return false;
        }
        clearFiles(filePathList);
        Log.i(TAG, "mergePCMFilesToWAVFile  success. " + new SimpleDateFormat("yyyy-MM-dd hh:mm").format(new Date()));
        return true;

    }

    /**
     * pcm to wav
     *
     * @param pcmPath       
     * @param destinationPath 
     * @param deletePcmFile  
     * @return
     */
    public static boolean makePCMFileToWAVFile(String pcmPath, String destinationPath, boolean deletePcmFile) {
        byte buffer[] = null;
        int TOTAL_SIZE = 0;
        File file = new File(pcmPath);
        if (!file.exists()) {
            return false;
        }
        TOTAL_SIZE = (int) file.length();
        WaveHeader header = new WaveHeader();

        header.fileLength = TOTAL_SIZE + (44 - 8);
        header.FmtHdrLeth = 16;
        header.BitsPerSample = 16;
        header.Channels = (short)AudioFormat.channelCountFromInChannelMask(WaveHeader.IN_CHANNELS);
        header.FormatTag = 0x0001;
        header.SamplesPerSec = WaveHeader.RATE;
        header.BlockAlign = (short) (header.Channels * header.BitsPerSample / 8);
        header.AvgBytesPerSec = header.BlockAlign * header.SamplesPerSec;
        header.DataHdrLeth = TOTAL_SIZE;

        byte[] h = null;
        try {
            h = header.getHeader();
        } catch (IOException e1) {
            Log.e(TAG, e1.getMessage());
            return false;
        }

        if (h.length != 44) return false;

        File destfile = new File(destinationPath);
        if (destfile.exists()) destfile.delete();

        try {
            buffer = new byte[1024 * 4]; // Length of All Files, Total Size
            InputStream inStream = null;
            OutputStream ouStream = null;

            ouStream = new BufferedOutputStream(new FileOutputStream(
                    destinationPath));
            ouStream.write(h, 0, h.length);
            inStream = new BufferedInputStream(new FileInputStream(file));
            int size = inStream.read(buffer);
            while (size != -1) {
                ouStream.write(buffer);
                size = inStream.read(buffer);
            }
            inStream.close();
            ouStream.close();
        } catch (FileNotFoundException e) {
            Log.e(TAG, e.getMessage());
            return false;
        } catch (IOException ioe) {
            Log.e(TAG, ioe.getMessage());
            return false;
        }
        if (deletePcmFile) {
            file.delete();
        }
        Log.i(TAG, "make PCM to " + destinationPath + " success. " 
                 + new SimpleDateFormat("yyyy-MM-dd hh:mm").format(new Date()));
        return true;

    }

    private static void clearFiles(List<String> filePathList) {
        for (int i = 0; i < filePathList.size(); i++) {
            File file = new File(filePathList.get(i));
            if (file.exists()) {
                file.delete();
            }
        }
    }
}